import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation

# 使用de_casteljau算法递归计算
def de_casteljau(control_points:list, t:float)->list:
    number = len(control_points)
    if number == 1:
        return control_points[0]
    new_points = []
    for i in range(number - 1):
        new_point = tuple(
            (1 - t) * control_points[i][j] + t * control_points[i + 1][j] \
                for j in range(len(control_points[i])))
        new_points.append(new_point)
    # 显示中间各阶辅助线
    x = [point[0] for point in new_points]
    y = [point[1] for point in new_points]
    ax.plot(x, y, marker='o', color = intermediate_line_colors[number - 2], markersize = 5)
    return de_casteljau(new_points, t)

def draw_bezier(t:float)->None:
    # 为了动画显示，需要清除之前的显示内容
    ax.clear()
    ax.axis('off')
    ax.set_title('t={:.2f}'.format(t), fontsize=15)
    curve_point = de_casteljau(control_points, t)
    curve_points.append(curve_point)
    # 显示贝塞尔曲线
    x = [point[0] for point in curve_points]
    y = [point[1] for point in curve_points]
    ax.plot(x, y, color = intermediate_line_colors[num_control_points - 1])
    # 显示控制点
    x = [point[0] for point in control_points]
    y = [point[1] for point in control_points]
    ax.scatter(x, y, s = 60, color='red')
    for index, point in enumerate(control_points):
        ax.text(point[0], point[1], 'P{}'.format(index), fontsize=13)
    # 显示控制多边形
    ax.plot(x, y, color='black')
    # 为了循环动画显示，当t到达1.0后需要清除curve_points里之前的数据
    if t >= 1.0:
        curve_points.clear()

# 设置字体为黑体，从而支持中文
plt.rcParams['font.family'] = 'SimHei'
control_points = [[1.0, 6.0], [1.5, 3.0], [6.5 , 3.0], [7.0, 6.0]]
num_control_points = len(control_points)
# 设置线的颜色映射
intermediate_line_colors = plt.cm.viridis(np.linspace(0, 1, num_control_points))
fig, ax = plt.subplots()
fig.canvas.manager.set_window_title('贝塞尔曲线动画演示')
t_values = np.linspace(0, 1, 100)
curve_points = []
animate_bezier = animation.FuncAnimation(fig, draw_bezier, t_values, interval = 10, repeat = True)
plt.show()
